/*
 * @desc 验证器
 * */
define(['query', 'objecter'], function(query, objecter){
    function Valider(){
        this.init.apply(this, arguments);
    }

    Valider.prototype = {
        //初始化
        init : function(options){
            this.options = {
                //是否验证不通过则中止继续
                errorPause : true,

                //单个验证成功执行函数
                onSuccess : null,

                //单个验证失败执行函数
                onError : null,

                //完成所有验证成功执行函数
                onCompleteSuccess : null,

                //完成所有验证失败执行函数
                onCompleteError : null,

                //靠元素name来归类元素(radio/checkbox除外)，默认false，即每个元素作独立验证
                nameValid : false,

                //隐藏元素是否验证，默认true
                hiddenValid : true
            };

            //前置规则
            this.frontRules = [];
            //规则列表
            this.rules = [];

            this.setOptions(options);

            ////添加默认required////
            this._addFrontMethod('required', function(value, elements, params){
                //是否必须验证
                var b = true, el = elements[0];
                if(this.classCheck(el, 'required') || this.attrCheck(el, 'required')){
                    b = /\S+/.test(value);
                }

                return b;
            }, 'required');
        },

        //配置
        setOptions : function(options){
            options = objecter.isPlainObject(options) ? options : {};
            for(var i in options){
                this.options[i] = options[i];
            }

            return this.options;
        },

        /**
         * @dsec 添加验证方法
         * */
        addMethod : function(name, valid, msg, isCover){
            this._addMethod(name, valid, msg, isCover, this.rules);
        },

        /**
         * @dsec 添加前置验证方法
         * */
        _addFrontMethod : function(name, valid, msg, isCover){
            this._addMethod(name, valid, msg, isCover, this.frontRules);
        },

        /**
         * @dsec 添加验证方法
         * @param <String> name 规则名称
         * @param <Function/RegExp> valid 规则验证函数，提供参数(value, element, params)，或正则表达式
         * @param <String/Function> msg 规则提示
         * @param <bool> isCover 同名是否覆盖，默认覆盖
         * */
        _addMethod : function(name, valid, msg, isCover, rules){
            var rule, b = false;
            rule = new Rule({
                name : name,
                valid : valid,
                message : msg
            });

            for(var i = 0; i < rules.length; i++){
                if(rules[i].name == name && isCover !== false){
                    rules[i] = rule;
                    b = true;
                    break;
                }
            }

            if(!b) rules.push(rule);
        },

        /**
         * @dsec 设置提示信息
         * @param <Object/String> 键值对，键：规则名称，值：提示信息  为字符串时即为键名
         * @param <String> 提示信息
         * */
        messages : function(messages, msg){
            if(typeof messages == 'string'){
                var temp = {};
                temp[messages] = msg;
                messages = temp;
            }
            messages = objecter.isPlainObject(messages) ? messages : {};
            change(this.frontRules, messages);
            change(this.rules, messages);

            //更改
            function change(rules, messages){
                for(var i = 0, rule; i < rules.length; i++){
                    rule = rules[i];
                    for(var j in messages){
                        if(rule.options.name == j && typeof messages[j] != 'undefined' && messages[j] != null){
                            rule.options.message = messages[j];
                        }
                    }
                }
            }
        },

        /**
         * @dsec 检测验证
         * @param <Object> el验证表单
         * @return <bool>
         * */
        isValid : function(el){
            var groups = this.groupElement(el),
                options = this.options,
                b = true;

            //对每个表单元素验证
            for(var i = 0, flag; i < groups.length; i++){
                flag = this._validGroup(groups[i]);
                if(!flag){
                    b = false;
                    if(options.errorPause) {
                        break;
                    }
                }
            }

            if(!b){
                if(objecter.isFunction(options.onCompleteError)){
                    options.onCompleteError(groups[i]);
                }
            }else{
                if(objecter.isFunction(options.onCompleteSuccess)){
                    options.onCompleteSuccess(groups);
                }
            }

            return b;
        },

        //验证元素组
        _validGroup : function(group){
            var options = this.options,
                bf = true, b = true;

            //前置验证
            for (var i = 0; i < this.frontRules.length; i++) {
                var rule = this.frontRules[i],
                    el = group.list[0],
                    attr = rule.getAttr(el);

                bf = rule.valid(group.getValue(), group.list, attr);
                if (!bf) {
                    if (objecter.isFunction(options.onError)) {
                        options.onError(group, rule.message(attr));
                    }
                    break;
                }
            }

            //常规验证，须在前置验证通过情况下才验证
            if(bf) {
                for (var i = 0; i < this.rules.length; i++) {
                    var rule = this.rules[i],
                        el = group.list[0],
                        attr = rule.getAttr(el);

                    if (rule.classCheck(el) || rule.attrCheck(el)) {
                        b = rule.valid(group.getValue(), group.list, attr);
                        if (!b) {
                            if (objecter.isFunction(options.onError)) {
                                options.onError(group, rule.message(attr));
                            }
                            break;
                        }
                    } else continue;
                }
            }
            b = bf ? (b ? b : false) : bf;

            //全部通过
            if(b && objecter.isFunction(options.onSuccess)){
                options.onSuccess(group);
            }

            return b;
        },

        /**
         * @dsec 元素分组，把各种不同类型的表单元素统一起来
         * @param <Dom/Selector> el验证表单
         * @return <bool>
         * */
        groupElement : function(el){
            var els, arr = [], list = {}, groups = [];
            els = query.find(el);

            //找出所有表单元素
            for(var i = 0, temp; i < els.length; i++){
                temp = els[i];
                if(/form/i.test(temp.tagName)){
                    arr = arr.concat(query.find('input,select,textarea', temp));
                }else if(/input|select|textarea/i.test(temp.tagName)){
                    arr = arr.concat(temp);
                }
            }

            //同名同类型表单分组
            for(var i = 0, nameValid = this.options.nameValid; i < arr.length; i++){
                var temp = arr[i],
                    spareName = ('name_' + Math.random()).replace('.', ''),
                    name = temp.name,
                    type, group;

                if(/textarea/i.test(temp.tagName)){
                    if(nameValid) spareName = temp.name || 'textarea';
                    type = 'textarea';
                }
                else if(/select/i.test(temp.tagName)){
                    if(nameValid) spareName = temp.name || 'select';
                    type = 'select';
                }
                else if(/radio/i.test(temp.type)){
                    spareName = 'select';
                    type = 'radio';
                }
                else if(/checkbox/i.test(temp.type)){
                    spareName = 'checkbox';
                    type = 'checkbox';
                }
                else if(/button|image|reset|submit/i.test(temp.type)){
					continue;
                }
                else{
                    if(nameValid) spareName = temp.name || 'text';
                    type = 'text';
                }

                //同名检测
                if(list[spareName]){
                    list[spareName].list.push(temp);
                }else{
                    list[spareName] = {
                        spareName : spareName,
                        name : name,
                        type : type,
                        list : [temp]
                    };
                }
            }

            for(var i in list){
                groups.push(new Group({
                    name : list[i].name,
                    type : list[i].type,
                    list : list[i].list
                }));
            }

            return groups;
        }
    };

    //规则
    function Rule(){
        this.init.apply(this, arguments);
    }

    Rule.prototype = {
        //初始化
        init : function(options){
            //配置
            var defaults = {
                name : null,
                valid : null,
                message : null,
                success : null,
                error : null
            };

            options = objecter.isPlainObject(options) ? options : {};
            for(var i in defaults){
                defaults[i] = options[i];
            }

            this.options = defaults;
        },

        /**
         * @dsec 检测验证
         * @param <String> value 表单值
         * @param <[Dom]> dom元素组 表单值
         * @param <String> param 规则参数值
         * @return <bool>
         * */
        valid : function(value, elements, params){
            var b = false,
                options = this.options,
                valid = objecter.isFunction(options.valid) ? options.valid : objecter.isRegexp(options.valid)
                    ? function(value){return options.valid.test(value)} : function(){return true};
            b = valid.call(this, value, elements, params) == true ? true : false;

            return b;
        },

        //获取错误信息
        message : function(params){
            var options = this.options,
                msg = options.message;

            if(typeof msg == 'function'){
                msg = msg.call(this, params);
            }else if(typeof msg == 'string'){
                params = this.formateParams(params);
                for(var i = 0; i < params.length; i++){
                    msg = msg.replace(new RegExp('\{\\s*' + i + '\\s*\}'), params[i]);
                }
            }

            return msg;
        },

        //类名检测
        classCheck : function(el, name){
            var b = false,
                className = (el.className || '').split(/\s+/);
            name = name || this.options.name;
            for(var i = 0; i < className.length; i++){
                if(className[i] == name){
                    b = true;
                    break;
                }
            }

            return b;
        },

        //属性名检测
        attrCheck : function(el, name){
            var b = false, attr = this.getAttr(el, name);
            if(attr === null) b = false;
            else{
                b = true;
            }

            return b;
        },

        //获取属性
        getAttr : function(el, name){
            var attr, dataAttr;
            name = name || this.options.name;
            attr = el.getAttribute(name);
            dataAttr = el.getAttribute(name);
            if(attr === null) attr = dataAttr;

            return attr;
        },

        //格式化参数
        formateParams : function(params){
            //参数解析
            if(objecter.isArray(params)){
                params = params;
            }else if(/^\[\d+(\,\d+)*\]$/.test(params)){
                params = new Function('return ' + params)();
            }else if(/\d+\,\d+/.test(params)){
                params = params.split(',');
            }else if(params === null || params === undefined){
                params = [];
            }else params = [params];

            return params;
        }
    };

    //表单组
    function Group(){
        this.init.apply(this, arguments);
    }

    Group.prototype = {
        ///属性//
        name : '',//名称
        type : '',//类型
        list : [],//元素数组

        init : function(options){
            for(var i in options){
                this[i] = options[i];
            }
        },

        //获取值
        getValue : function(){
            var value = '', arr = [];

            for(var i = 0, temp, v; i < this.list.length; i++){
                temp = this.list[i];
                v = temp.value || '';
                if(/radio|checkbox/.test(this.type) && temp.checked) arr.push(v);
                else arr.push(v);
            }
            value = arr.join(',');

            return value;
        }
    };

    return Valider;
});